package event

import (
	"fmt"
	"log/slog"
	"reflect"
	"strings"
	"sync"
)

type eventDispatch struct {
	bus        *eventBus                     // 事件总线
	count      int                           // 订阅量统计
	subscriber map[string][]*eventSubscriber // 订阅信息 eventName=>[]eventSubscriber
	states     map[string]bool               // 事件的可用状态 eventName=>state
	mu         sync.RWMutex
}
type eventSubscriber struct {
	handler EventHandler
	pc      uintptr // 缓存订阅函数注册时缓存的调用栈入口, 供重置 slog.Record.PC 使用
	isOnce  bool    // 是否仅订阅一次
	isSync  bool    // 是否同步执行
}

func newEventDispatch(bus *eventBus) *eventDispatch {
	d := new(eventDispatch)
	d.bus = bus
	d.subscriber = make(map[string][]*eventSubscriber)
	d.states = make(map[string]bool)
	return d
}

// subscribe 异步方式订阅事件(长期订阅)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventDispatch) subscribe(eventName string, eventHandler EventHandler) error {
	return e.doSubscribe(eventName, eventHandler, false, false)
}

// subscribeOnce 异步方式订阅事件(仅订阅一次)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventDispatch) subscribeOnce(eventName string, eventHandler EventHandler) error {
	return e.doSubscribe(eventName, eventHandler, true, false)
}

// subscribeSync 同步方式订阅事件(长期订阅)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventDispatch) subscribeSync(eventName string, eventHandler EventHandler) error {
	return e.doSubscribe(eventName, eventHandler, false, true)
}

// subscribeSyncOnce 同步方式订阅事件(仅订阅一次)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventDispatch) subscribeSyncOnce(eventName string, eventHandler EventHandler) error {
	return e.doSubscribe(eventName, eventHandler, true, true)
}
func (e *eventDispatch) doSubscribe(eventName string, eventHandler EventHandler, isOnce, isSync bool) error {
	e.mu.Lock()
	defer e.mu.Unlock()
	if v, ok := e.states[eventName]; ok {
		if !v {
			// 已被禁用的事件, 无法订阅
			e.bus.log(e.bus.getEntryPC(5), slog.LevelWarn, "eventDispatch.doSubscribe["+eventName+"], eventName that are disabled cannot be subscribed to")
			return ErrEventDisable
		}
	}
	if _, ok := e.states[eventName]; ok {
		e.subscriber[eventName] = append(e.subscriber[eventName], &eventSubscriber{
			handler: eventHandler,
			pc:      e.bus.getEntryPC(5),
			isOnce:  isOnce,
			isSync:  isSync,
		})
	} else {
		e.subscriber[eventName] = []*eventSubscriber{{
			handler: eventHandler,
			pc:      e.bus.getEntryPC(5),
			isOnce:  isOnce,
			isSync:  isSync,
		}}
		e.states[eventName] = true // 新增事件，设置默认状态为启用
	}

	e.count++
	e.bus.log(e.bus.getEntryPC(5), slog.LevelDebug, "eventDispatch.doSubscribe["+eventName+"] succeed")
	return nil
}

// unsubscribe 取消订阅事件
//   - eventName 事件名称
//   - eventHandler 回调函数(订阅事件时的同一个回调函数)
func (e *eventDispatch) unsubscribe(eventName string, eventHandler EventHandler) error {
	e.mu.Lock()
	defer e.mu.Unlock()
	if e.count == 0 {
		// 没有任何事件订阅
		return nil
	}
	handlerPointer := reflect.ValueOf(eventHandler).Pointer()
	// 检查订阅的事件
	if list, ok := e.subscriber[eventName]; ok {
		// 删除订阅
		subscribers := make([]*eventSubscriber, len(list))
		index := 0
		for _, subscriber := range list {
			if reflect.ValueOf(subscriber.handler).Pointer() == handlerPointer {
				e.count--
				e.bus.log(e.bus.getEntryPC(4), slog.LevelDebug, "eventDispatch.unsubscribe["+eventName+"], remove handler succeed")
			} else {
				subscribers[index] = subscriber
				index++
			}
		}
		e.subscriber[eventName] = subscribers[:index]
	}
	return nil
}

// publish 发布事件, 触发事件广播
//   - eventName 事件名称
//   - data 事件参数
func (e *eventDispatch) publish(eventName string, data EventData) error {
	e.mu.RLock()
	defer e.mu.RUnlock()
	if e.count == 0 {
		// 没有任何事件订阅
		return nil
	}
	if v, ok := e.states[eventName]; !ok {
		// 事件未订阅/不存在
		return ErrEventDisable
	} else if !v {
		// 事件已被禁用
		return ErrEventDisable
	}
	e.bus.log(e.bus.getEntryPC(4), slog.LevelDebug, "Publish ["+eventName+"]")
	// 触发事件广播
	// 检查异步方式订阅的事件
	if list, ok := e.subscriber[eventName]; ok {
		for index := 0; index < len(list); {
			if list[index].isSync {
				e.executeHandler("Publish [broadcast:sync]", eventName, list[index], data)
			} else {
				go e.executeHandler("Publish [broadcast:async]", eventName, list[index], data)
			}
			// 删除订阅
			if list[index].isOnce {
				e.count--
				list = append(list[:index], list[index+1:]...)
			} else {
				index++
			}
		}
		e.subscriber[eventName] = list
	}
	return nil
}

// executeHandler 执行订阅事件的回调函数
func (e *eventDispatch) executeHandler(publish string, eventName string, subscriber *eventSubscriber, data EventData) {
	// 捕获任务执行异常状态
	defer func(eventName string, subscriber *eventSubscriber, data EventData) {
		if err := recover(); err != nil {
			e.bus.logAttrs(
				subscriber.pc, // 订阅函数注册时缓存的调用栈
				slog.LevelError,
				fmt.Sprintf("%s executeHandler[%s] panic", publish, eventName),
				slog.Any("data", data),
				slog.Any("error", err),
			)
			return
		}
	}(eventName, subscriber, data)
	if err := subscriber.handler(data); err != nil {
		e.bus.logAttrs(
			subscriber.pc, // 订阅函数注册时缓存的调用栈
			slog.LevelError,
			fmt.Sprintf("%s executeHandler[%s] error", publish, eventName),
			slog.Any("data", data),
			slog.String("error", err.Error()),
		)
	} else {
		e.bus.log(subscriber.pc, slog.LevelDebug, fmt.Sprintf("%s executeHandler[%s] succeed", publish, eventName))
	}
}

// state 获取某一个事件的状态
//   - eventName 事件名称
func (e *eventDispatch) state(eventName string) bool {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.bus.log(e.bus.getEntryPC(4), slog.LevelWarn, "eventDispatch.state, eventName cannot be empty")
		return false
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	if state, ok := e.states[eventName]; ok {
		return state
	} else {
		return false
	}
}

// disabled 禁用某一个事件
//   - eventName 事件名称
func (e *eventDispatch) disabled(eventName string) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.bus.log(e.bus.getEntryPC(4), slog.LevelWarn, "eventDispatch.disabled, eventName cannot be empty")
		return ErrEventName
	}
	e.mu.Lock()
	defer e.mu.Unlock()
	if _, ok := e.states[eventName]; ok {
		e.states[eventName] = false
		return nil
	}
	return ErrEventName
}

// enabled 启用某一个事件
//   - eventName 事件名称
func (e *eventDispatch) enabled(eventName string) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.bus.log(e.bus.getEntryPC(4), slog.LevelWarn, "eventDispatch.enabled, eventName cannot be empty")
		return ErrEventName
	}
	e.mu.Lock()
	defer e.mu.Unlock()
	if _, ok := e.states[eventName]; ok {
		e.states[eventName] = true
		return nil
	}
	return ErrEventName
}

// getEvents 获取事件订阅信息
func (e *eventDispatch) getEvents() (info EventsInfo) {
	e.mu.RLock()
	defer e.mu.RUnlock()
	info = EventsInfo{Count: 0, Events: make(map[string]int)}
	if e.count > 0 {
		info.Count += e.count
		for eventName, subscribers := range e.subscriber {
			if _, ok := info.Events[eventName]; !ok {
				info.Events[eventName] = len(subscribers)
			} else {
				info.Events[eventName] += len(subscribers)
			}
		}
	}
	return
}
